<!--
 * @Description: 
 * @Author: xuechengwu
 * @Email: xuechengwu@myhexin.com
 * @Date: 2021-11-20 16:16:56
 * @LastEditTime: 2022-02-11 17:23:42
 * @LastEditors: xuechengwu
-->
<template>
    <component
      :is="config.name"
      v-bind="linkData"
      v-on:click="onSelect"
      :data-mark="config.mark"
      :data-parents="parents.join(',')"
      :class="['vdr', vdrStyle]"
      @event="eventEmit"
    >
      <div
        v-if="config.isContainer"
        ref="container"
        class="sortable-box"
        :style="config.container"
      >
        <template v-for="child in config.components || []">
            <vdr
                :key="child.mark"
                :config="child"
                :parents="parents.concat(config.mark)"
                @droped="childDropped"
                @sorted="childSorted"
                :currentMark="currentMark"
                :is-edit="isEdit"
                :datas="datas"
                :page="page"
                @selected="(data) => $emit('selected', data)"
                :values="values"
            />
        </template>
      </div>
    </component>
</template>

<script>
import Sortable from 'sortablejs';
import _ from 'lodash';
import A5 from '../A5';

export default {
    props: ['config', 'parents', 'currentMark', 'values', 'datas', 'page', 'isEdit'],
    mounted() {
      if (this.config.isContainer && this.isEdit) {
        new Sortable(this.$refs.container, {
          onEnd: (evt) => {
              const { newIndex, oldIndex } = evt;
              const { mark } =this. config;
              this.$emit('sorted', { parent: this.parents.concat(mark), newIndex, oldIndex });
          }
        });
        this.$refs.container.addEventListener('drop', this.dropListener);
        this.$refs.container.addEventListener('dragover', this.dragOver);
        this.$refs.container.addEventListener('dragenter', this.dragEnter);
        
      }
    },
    computed: {
      vdrStyle() {
        const { config, currentMark } = this;
        const { mark } = config;
        if (`${mark}` === `${currentMark}`) {
          return 'active';
        }
        return '';
      },
      linkData() {
        const { values, datas } = this;
        const { data, links = [] } = this.config;
        const targetObj = { data: _.cloneDeep(data) };
        links.forEach((vo) => {
          const { source, selectedKey, path, type } = vo;
          const targetValue = values[source];
          let value = '';
          if (type === 0) {
            value = selectedKey.split('.').reduce((cur, key) => {
              return cur[key];
            }, targetValue);
          } else if (type === 1) {
            const targetData = datas[source];
            if (targetData) {
              value = targetData.value;
            }
          } else if (type === 2) {
            // TODO: 如果当前数据是从list中获取
          }
          
          path.split('.').reduce((cur, key, index, array) => {
            if (array.length - 1 === index) {
              cur[key] = value
            }
            return cur[key];
          }, targetObj);
        });
        return targetObj.data;
      }
    },
    methods: {
      onSelect(e) {
        e.stopPropagation();
        const { parents = [], config } = this;
        const { mark } = config;
        console.log('vdr selected==>', mark);
        this.$emit('selected', { parents, mark }); 
      },
      dropListener(e) {
        e.stopPropagation();
        this.$emit('droped', [...this.parents, this.config.mark]);
      },
      childDropped(parent) {
        this.$emit('droped', parent);
      },
      dragOver(e) {
        e.preventDefault();
      },
      dragEnter(e) {
        e.preventDefault();
      },
      childSorted(data) {
        this.$emit('sorted', data);
      },
      updatePageData(links, data) {
        const { page } = this;
        const changes = links.map(vo => {
          const { key, type, value = '' } = vo;
          if (Number(type) === -1) {
            return {
              path: `datas.${key}.value`,
              value,
            };
          } else {
            return {
              path: `datas.${key}.value`,
              value: data,
            };
          }
        });
        this.$store.commit('UPDATE_PAGE', {
          mark: page.mark,
          changes,
        });
      },
      eventEmit(e) {
        const { name, data } = e;
        const { config, page } = this;
        const { events = [] } = config;
        const targetEvent = events.find(vo => vo.name === name);
        console.log('event name===>', name, targetEvent, events);
        if (targetEvent) {
          if (targetEvent.key === 'SYS_PAGE_DATA_EDIT') {
            const { params = {} } = targetEvent;
            const { links = [] } = params;
            this.updatePageData(links, data);
          } else if (targetEvent.key === 'SYS_ROUTER') {
            // TODO: 执行路由操作
          } else if (targetEvent.key === 'SYS_REQUEST') {
            // TODO: 执行请求发送操作
          } else if (targetEvent.key === 'NONE') {
            // 无操作
          } else {
            const componentConfig = A5.getComponent(config.name);
            const { events: configEvents = {} } = componentConfig.config;
            const { funcs = [] } = configEvents[name];
            console.log('target key===>', targetEvent, funcs);
            const func = funcs.find(vo => vo.key === targetEvent.key);
            console.log('func===>', func);
            if (func && func.callback) {
              func.callback({
                updateComponent: (path, value) => {
                  this.$store.commit('UPDATE_COMPONENT', {
                    changes: [{
                      path,
                      value,
                    }],
                  });
                },
                updatePage: (path, value) => {
                  this.$store.commit('UPDATE_PAGE', {
                    mark: page.mark,
                    changes: [{
                      path,
                      value,
                    }],
                  });
                },
                data: page,
              }, config, data);
            }
          }
          
        }
        
      }
    },
    beforeDestroy() {
      if (this.config.isContainer) {
        if (this.$refs.container) {
          this.$refs.container.removeEventListener('drop', this.dropListener);
          this.$refs.container.removeEventListener('dragover', this.dragOver);
          this.$refs.container.removeEventListener('dragenter', this.dragEnter);
        }
      }
    }
}
</script>

<style lang="less" scoped>
.vdr {
  &.active {
    border: solid 2px rgb(250, 113, 34);
    position: relative;
  }
}
</style>